package com.tmpt.controller.taglib.generic;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import javax.annotation.Resource;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.BodyTagSupport;

import org.apache.log4j.Logger;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

public class GenericTag<T> extends BodyTagSupport{
	private Logger log = Logger.getLogger(this.getClass());
	
	private static final long serialVersionUID = 1L;
	
	private String className;
	private String methodName;
	private Map<String,Object> paramMap = new HashMap<String, Object>(); 
	private Boolean isUse = true;
	private String scope = "pageContext";
	private String paramScope ;
	
	public void put(String key, String value){
		//System.out.println("paramMap.put(key, value):"+key+ " "+value);
		paramMap.put(key, value);
	}
	
	@SuppressWarnings("unchecked")
	public Object execute(){
		//System.out.println(className);
		//System.out.println(this+" "+scope);
		//System.out.println("paramMap:"+paramMap.size());
		try{
						
			T t = (T)Class.forName(className).newInstance();
			Method method = null;
			Object o  = null;
			
			//invoke spring 
			ApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(pageContext.getServletContext());
			
			Field[] fields = t.getClass().getDeclaredFields();
			for(Field field:fields){
				Resource resourceAnno = field.getAnnotation(Resource.class);
				if(resourceAnno==null) continue;
				String serviceName = field.getName();
				field.setAccessible(true);
				if(resourceAnno.name()!=null && !resourceAnno.name().trim().equals("")){
					if(resourceAnno.name().equals("pageContext")){
						//注入pageContext
						field.set(t, pageContext);
					}else{
						serviceName=resourceAnno.name();
						field.set(t, ctx.getBean(serviceName));
					}
				}else{
					field.set(t, ctx.getBean(serviceName));
				}
			}
			
			
			//调用方法
			if(paramMap!=null && paramMap.size()!=0){
				method = t.getClass().getMethod(methodName,Map.class);
				o  = method.invoke(t,paramMap);
				paramMap.clear();
			}else{
				method = t.getClass().getMethod(methodName);
				o  = method.invoke(t);
			}
			
			return o;
		}catch(Exception e){
			e.printStackTrace();
			log.error(e);
		}
		return null;
	}
	
	@Override
	public int doStartTag() throws JspException {
		return super.doStartTag();
	}

	public int doEndTag() throws JspException {		
		if(isUse == true){
			Object result = this.execute();
			if(scope.equals("session")){
				pageContext.getSession().setAttribute(id, result);
			}
			else if(scope.equals("request")){
				pageContext.getRequest().setAttribute(id, result);
			}
			else{
				pageContext.setAttribute(id, result);
			}
			
			if(paramScope!=null){
				if(paramScope.equals("session")){
					pageContext.getSession().setAttribute(id+"_paramScope", this.paramMap);
				}
				else if(paramScope.equals("request")){
					pageContext.getRequest().setAttribute(id+"_paramScope", this.paramMap);
				}
			}
		}
		return super.doEndTag();
	}

	public void release() {
		super.release();
		id = null;
	}
	
	public String getClassName() {
		return className;
	}
	public void setClassName(String className) {
		this.className = className;
	}
	public String getMethodName() {
		return methodName;
	}
	public void setMethodName(String methodName) {
		this.methodName = methodName;
	}
	public Boolean getIsUse() {
		return isUse;
	}
	public void setIsUse(Boolean isUse) {
		this.isUse = isUse;
	}
	public Map<String, Object> getParamMap() {
		return paramMap;
	}
	public void setParamMap(Map<String, Object> paramMap) {
		this.paramMap = paramMap;
	}
	public String getScope() {
		return scope;
	}
	public void setScope(String scope) {
		this.scope = scope;
	}

	public String getParamScope() {
		return paramScope;
	}

	public void setParamScope(String paramScope) {
		this.paramScope = paramScope;
	}

}
